package tests;

import network.Device;
import network.Network;
import network.Rule;

import java.util.HashMap;

public class DCTopoConstructor {
    private static Network n = new Network();
    private static HashMap<Integer, String> deviceToName = new HashMap<>();

    private static void addLink(int x, String xs, int y) {
        n.addLink(deviceToName.get(x), deviceToName.get(x) + xs, deviceToName.get(y), deviceToName.get(y));
    }

    public static Network getNetwork(int C, int A, int M, int E) {
        int cid = 0, aid = cid + C, eid = aid + A * M;
        int tot = eid + A * E;

        n.addDevice("default");
        for (int i = cid; i < aid; i ++) {
            deviceToName.put(i, "core " + i);
            n.addDevice(deviceToName.get(i));
        }
        for (int i = aid; i < eid; i ++) {
            deviceToName.put(i, "aggr " + i);
            n.addDevice(deviceToName.get(i));
        }
        for (int i = eid; i < tot; i ++) {
            deviceToName.put(i, "server " + i);
            n.addDevice(deviceToName.get(i));
        }
        for (String name : deviceToName.values()) {
            n.addLink(name, "default", "default", name + "-peer-default");
        }

        int h = M / 2;
        for (int i = 0; i < C; i ++) {
            for (int j = 0; j < A; j ++) {
                for (int k = 0; k < h; k ++) {
                    int t = aid + j * M + k;
                    addLink(i, "-down", t);
                    addLink(i, "-down" + j, t);
                    addLink(t, "-up", i);
                }
            }
        }

        for (int i = 0; i < A; i ++) {
            int t = aid + i * M;
            for (int j = 0; j < h; j ++) {
                for (int k = 0; k < h; k ++) {
                    addLink(t + j, "-down", t + h + k);
                    addLink(t + h + k, "-up", t + j);
                }
            }
        }

        /*
        for (int i = 0; i < A; i ++) {
            for (int j = 0; j < h; j ++) {
                int t = aid + i * M + h + j;
                for (int k = 0; k < E; k ++) {
                    int s = eid + i * E + k;
                    addLink(t, "down", s);
                    addLink(s, "up", t);
                }
            }
        }
         */

        String name;
        Device device;
        Rule rule;

        for (int dst = 0; dst < A; dst ++) {
            for (int i = 0; i < A; i ++) {
                for (int j = 0; j < M; j ++){
                    name = deviceToName.get(aid + i * M + j);
                    device = n.getNameToDevice().get(name);
                    if (i == dst) {
                        rule = new Rule(device, dst, 32, device.getPortByName(name + "-down"));
                    } else {
                        rule = new Rule(device, dst, 32, device.getPortByName(name + "-up"));
                    }
                    n.addInitialRules(rule);
                }
            }
            for (int i = 0; i < C; i ++) {
                name = deviceToName.get(i);
                device = n.getNameToDevice().get(name);
                rule = new Rule(device, dst, 32, device.getPortByName(name + "-down" + dst));
                n.addInitialRules(rule);
            }
        }

        return n;
    }
}
